package norbert.flickr.controls {
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	import mx.containers.Canvas;
	import mx.core.Application;
	import mx.core.ScrollPolicy;
	import mx.effects.Move;
	import mx.effects.Parallel;
	import mx.effects.Zoom;
	import mx.events.EffectEvent;
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.events.ResizeEvent;
	import mx.effects.Fade;
	
	public class ZoomPhotoImage extends Canvas {
		/* PROPERTIES */
		
		/*private*/ 
		
		private static var logger: ILogger = Log.getLogger("norbert.flickr.controls.ZoomPhotoImage");
		
		private var photoImage: PhotoImage;
		private var maskCanvas: Canvas;
		
		private var parallelEffect: Parallel;
		private var zoomEffect: Zoom;
		private var moveEffect: Move;
		private var fadeInEffect: Fade;
		
		private var animating: Boolean = false;
		private var dragging: Boolean = false;
		
		private var zoomMode: int = 0;
		
		/* public */
		
		[Bindable]
		public var zoomDuration : Number = 500;
		[Bindable]
		public var fadeDuration : Number = 300;

		private var _size: String = null;
		[Bindable]
		[Inspectable(category="General", enumeration="s,t,m,b")]
		public function get size(): String {
			return _size;
		}
		public function set size(value: String): void {
			_size = value;
			invalidateProperties();
		}
		
		private var _photo: XML = null;
		[Bindable]
		public function get photo(): XML {
			return _photo;
		}
		public function set photo(value: XML): void {
			_photo = value;
			invalidateProperties();
		}
		
		/* CONSTRUCTOR */
		
		public function ZoomPhotoImage() {
			horizontalScrollPolicy = ScrollPolicy.OFF;
			verticalScrollPolicy = ScrollPolicy.OFF;
			
			Application.application.addEventListener(MouseEvent.MOUSE_UP, onApplicationMouseUp);
			addEventListener(ResizeEvent.RESIZE, onResize);
		}
		
		/* EVENT HANDLERS */
		
		private function onApplicationMouseUp(event: MouseEvent): void {
			if (dragging) {
				photoImage.stopDrag();
			}
		}
		private function onImageMouseMove(event: MouseEvent): void {
			if (!dragging && event.buttonDown) {
				dragging = true;
				photoImage.startDrag();
			}
		}
		private function onImageMouseClick(event: Event): void {
			if (dragging) {
				dragging = false;
			} else {
				if (zoomMode == 0) {
					zoomMode = 1;
					zoom(1);
				} else if (zoomMode == 1) {
					zoomMode = 0;
					zoom(getFitToCanvasFactor());
				}
			}
		}
		
		private function onImageOpen(event: Event): void {
			photoImage.visible = false;
		}
		private function onImageComplete(event: Event): void {
			fitToCanvas();
			fadeInEffect.play();
			photoImage.visible = true;
		}
		
		private function onResize(event: ResizeEvent): void {
			if (zoomMode == 1) {
				zoom(1);
			} else if (zoomMode == 0) {
				zoom(getFitToCanvasFactor());
			}
		}
		
		/* METHODS */
		
		private function getFitToCanvasFactor(): Number {
			return Math.min(width / photoImage.contentWidth, height / photoImage.contentHeight);
		}
		
		private function centerImage(): void {
			photoImage.x = (width - photoImage.width)/2;
			photoImage.y = (height - photoImage.height)/2;
		}
		
		private function fitToCanvas(): void {
			var ratio: Number;
			
			if (photoImage.contentWidth > width || photoImage.contentHeight > height) {
				ratio = getFitToCanvasFactor();
			} else {
				ratio = 1;
			}
			
			photoImage.scaleX = ratio;
			photoImage.scaleY = ratio;
			
			photoImage.x = (width - photoImage.contentWidth * photoImage.scaleX)/2;
			photoImage.y = (height - photoImage.contentHeight * photoImage.scaleY)/2;
			
			zoomMode = 0;
		}
		

		private function zoom(factor: Number ): void {
			if (parallelEffect.isPlaying) {
				parallelEffect.end();
			}
			
			zoomEffect.zoomHeightTo = factor;
			zoomEffect.zoomWidthTo = factor;
			
			moveEffect.xTo = (width - photoImage.contentWidth * factor)/2;
			moveEffect.yTo = (height - photoImage.contentHeight * factor)/2;
			
			parallelEffect.play();
		}
		
		override protected function createChildren(): void {
			super.createChildren();
			
			if (!maskCanvas) {
				maskCanvas = new Canvas();
				addChild(maskCanvas);
				maskCanvas.setStyle("backgroundColor", 0xFF0000);
				maskCanvas.percentWidth = 100;
				maskCanvas.percentHeight = 100;
			}

			if (!photoImage) {
				photoImage = new PhotoImage();
				addChild(photoImage);
				photoImage.mask = maskCanvas;
				photoImage.visible = false;
				photoImage.addEventListener(MouseEvent.MOUSE_MOVE, onImageMouseMove);
				photoImage.addEventListener(MouseEvent.CLICK, onImageMouseClick);
				photoImage.addEventListener(Event.OPEN, onImageOpen);
				photoImage.addEventListener(Event.COMPLETE, onImageComplete);
			}
			
			if (!parallelEffect) {
				parallelEffect = new Parallel();
				
				zoomEffect = new Zoom(photoImage);
				parallelEffect.addChild(zoomEffect);
				zoomEffect.duration = zoomDuration;
				
				moveEffect = new Move(photoImage);
				parallelEffect.addChild(moveEffect);
				moveEffect.duration = zoomDuration;
			}
			
			if (!fadeInEffect) {
				fadeInEffect = new Fade(photoImage);
				fadeInEffect.duration = fadeDuration;
			}
		}
		
		override protected function commitProperties(): void {
			super.commitProperties();
			
			if (photoImage) {
				photoImage.photo = photo;
				photoImage.size = size;
			}
		}
	}
}
